'''
Created on May 7, 2011

@author: james
'''

from Doctors import Doctors
from EvaluatorHelper import EvaluatorHelper
from AggregateCall import AggregateCall

class CallCycleAndNumberCallsEvaluator(object):
    '''
    doctor cannot be assigned multiple shifts in same day
    '''

    def __init__(self, callIndex, callTally, initCount):
        self._callIndex = callIndex
        #self._callTally = callTally
        self._initCount = initCount
        
        self._callTally = map(AggregateCall.sumCalls, callTally)
                
    def __calculateNumberQ1Q2Calls(self, chromosome, debug):
        '''
        calculate number of q1 calls and number of q2 calls
        also calculate call count
        '''
        
        counts = self._initCount.copy()        

        q1Doctor = -1
        q2Doctor = -1
        
        numberQ1 = 0
        numberQ2 = 0
        
        for i in range(len(self._callIndex)):
            index = self._callIndex[i]
            
            doctor = chromosome[index]
            #if debug: print "Doctor: %s" % Doctors().doctorNames[doctor]
            
            if i < len(self._callIndex) - 2:
                nextCallIndex = self._callIndex[i + 2]
                
                #if debug: print "Index %d, next call index %d" % (index, nextCallIndex)
                
                #if debug: print "Index: %d, next: (%d:%d) %s" % (index, index + 1, nextCallIndex, chromosome[index +1 : nextCallIndex])
                if doctor in chromosome[index + 1: nextCallIndex]:
                    if debug: print "Q1: %s" % Doctors().doctorNames[doctor]
                    numberQ1 += 1
            else:
                '''
                need to check last calls
                '''
                if doctor in chromosome[index + 1: ]:
                    if debug: print "Q1: %s" % Doctors().doctorNames[doctor]
                    numberQ1 += 1

            if q2Doctor != -1 and doctor == q2Doctor:
                if debug: print "Q2: %s" % Doctors().doctorNames[doctor]
                numberQ2 += 1     
                
            counts[doctor] += 1
            
            q2Doctor = q1Doctor
            q1Doctor = doctor
            
        return [numberQ1, numberQ2, counts]

    def evaluate(self, chromosome, debug = False):
        '''
        rules about call cycle
        cannot have same doctor on consecutive calls
        q1 call is not allowed
        q2 call is not preferred
        q3 call is best solution
        doctors should have equal number of calls
        '''
        
        [numberQ1, numberQ2, counts] = self.__calculateNumberQ1Q2Calls(chromosome, debug)
        
        score = len (self._callIndex)
        
        if debug: print "Max score: %d, number q1: %d, number q2: %d" % (score, numberQ1, numberQ2)
        
        score -= numberQ1 * 2
        score -= numberQ2
        
        if debug: print counts
        
        distScore = EvaluatorHelper.calculateDistributionPenalty(counts, len (self._callIndex), len (self._initCount), score)
        score -= distScore
        
        if debug: print "CallCycleAndNumberCallsEvaluator dist penalty %d, score: %d" % (distScore, score)
        
        return score #0 if score < 0 else score        
    
    def evaluateConvergenceCriteria(self, chromosome, attempt):
        
        [numberQ1, _, _] = self.__calculateNumberQ1Q2Calls(chromosome, False)
        
        return numberQ1 == 0
        
        
    